package com.algebra.active.service.logic;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.algebra.active.domain.AuditLog;
import com.algebra.active.domain.CurrentTask;
import com.algebra.active.domain.WorkflowNodeDto;
import com.algebra.active.service.AuditlogService;
import com.algebra.active.service.CurrenttaskService;
import com.algebra.active.service.IBaseWorkflowService;
import com.algebra.active.service.WorkflowNodeService;
import com.algebra.active.util.ServiceApiResult;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.runtime.ProcessInstance;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author al
 * @date 2020/6/11 8:46
 * @description
 */
@Service
@Slf4j
public class BaseWorkflowServiceImpl implements IBaseWorkflowService {


    @Autowired
    RuntimeService runtimeService;
    @Autowired
    TaskService taskService;
    @Autowired
    CurrenttaskService currentTaskService;
    @Autowired
    AuditlogService auditLogService;
    @Autowired
    WorkflowNodeService nodeService;


    /**
     * 初始化流程
     *
     * @param param 流程初始化参数
     * @return 初始化结果
     */
    @Override
    public ServiceApiResult<Map<String, Object>> initWorkflow(Map<String, Object> param) {
        log.info("初始化工作流，接收到请求参数：{}", JSONUtil.toJsonStr(param));
        ServiceApiResult<Map<String, Object>> result = new ServiceApiResult<>();
        try {
            String procDefId = String.valueOf(param.get("procDefId"));
            String bussKey = String.valueOf(param.get("bussKey"));
            String userId = String.valueOf(param.get("userId"));
            log.info("[流程初始化]:流程定义ID =  {}，业务主键 = {}", procDefId, bussKey);
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(procDefId, bussKey);
            String procInstId = processInstance.getId();
            log.info("[流程初始化成功]申请单关联的流程ID = {}", procInstId);
            TaskEntity taskEntity = this.findRunTaskByInstId(procInstId);
            if (taskEntity == null) {
                log.info("任务实例未找到!");
                result.setSuccess(false);
                result.setMessage("初始化工作流异常，任务实例未找到！");
                return result;
            }
            CurrentTask currentTask = new CurrentTask();
            currentTask.setBusinessId(bussKey);
            currentTask.setTaskId(taskEntity.getId());
            currentTask.setInstanceId(procInstId);
            currentTask.setNodeId(taskEntity.getTaskDefinitionKey());
            // 用户和角色
            currentTask.setType(2);
            // 状态为已保存
            currentTask.setStatus("0");
            currentTask.setCreatedById("system");
            currentTask.setCreatedAt(new Date());
            currentTaskService.insertSelective(currentTask);

            log.info("流程初始化节点的任务：{}, 默认由第一节点提交到第二节点！", taskEntity.toString());
            param.put("procInstId", procInstId);
            result = this.completeMyTask(param);

        } catch (Exception e) {
            e.printStackTrace();
            log.error("初始化工作流接口调用异常，\n exp-msg:{}, \n stack-trace:{}", e.getMessage(), e.getStackTrace());
            result.setMessage("初始化工作流接口调用异常, exp-msg:" + e.getMessage());
            result.setSuccess(false);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return result;
    }


    /**
     * 获取实例正在运行的任务
     *
     * @param instId 流程实例ID
     * @return TaskEntity
     */
    private TaskEntity findRunTaskByInstId(String instId) {
        return (TaskEntity) taskService.createTaskQuery()
                .processInstanceId(instId)
                .active()
                .singleResult();
    }

    /**
     * 推动流程节点
     *
     * @param param 推动节点参数
     * @return 推动节点结果
     */
    @Override
    public ServiceApiResult<Map<String, Object>> completeMyTask(Map<String, Object> param) {
        log.info("推动工作流节点，接收到请求参数：{}", JSONUtil.toJsonStr(param));
        ServiceApiResult<Map<String, Object>> result = new ServiceApiResult<>();
        try {
            String clientId = String.valueOf(param.get("clientId"));

            String procInstId = String.valueOf(param.get("procInstId"));
            String bussKey = String.valueOf(param.get("bussKey"));
            String userId = String.valueOf(param.get("userId"));
            String userName = String.valueOf(param.get("userName"));
            String applyStatus = String.valueOf(param.get("applyStatus"));
            String comment = String.valueOf(param.get("comment"));
            if (applyStatus == null || "".equals(applyStatus)) {
                applyStatus = "0";
            }
            log.info("[工作流推动]当前流程ID = {}, 当前业务主键 = {}", procInstId, bussKey);
            TaskEntity taskEntity = this.findRunTaskByInstId(procInstId);
            if (taskEntity == null) {
                log.info("任务实例未找到!");
                result.setSuccess(false);
                result.setMessage("初始化工作流异常，任务实例未找到！");
                return result;
            }
            String nodeId = taskEntity.getTaskDefinitionKey();
            log.info("当前流程所在节点的任务 = {}, NodeId = {}", taskEntity.toString(), taskEntity.getTaskDefinitionKey());

            String procDefId = taskEntity.getProcessDefinitionId().split(":")[0];
            log.info("流程定义ID = {}", procDefId);

            // 查询上下级关系表，获取下级节点操作员信息
            WorkflowNodeDto curNode = nodeService.getCurrentNodeInfo(nodeId, procDefId, clientId);
            WorkflowNodeDto nextNode = nodeService.getNextNodeInfo(nodeId, applyStatus, procDefId, clientId);
            log.info("\n 当前节点信息：{} \n 目标节点信息：{}", JSONUtil.toJsonStr(curNode), JSONUtil.toJsonStr(nextNode));

            // 处理指定操作人的情况
            String designOprId = String.valueOf(param.get("designOprId"));
            if (designOprId != null && !"".equals(designOprId)) {
                log.info("指定操作人ID不为空，designOprId = {}", designOprId);
                nextNode.setRoleName("DesignatedOperator");
                nextNode.setRoleId(designOprId);
            }

            Map<String, Object> variables = new HashMap<>();
            variables.put("apply_status", applyStatus);
            variables.put("apply_status_code", nextNode.getNodeStatusCode());
            variables.put("apply_status_Name", nextNode.getNodeStatusName());
            variables.put("next_opr_Id", nextNode.getRoleId());
            variables.put("next_opr_name", nextNode.getRoleName());

            log.info("流程变量：{}", variables.toString());
            Authentication.setAuthenticatedUserId("user_key_" + userName + "@id_" + userId + "");
            taskService.addComment(taskEntity.getId(), procInstId, comment == null ? "" : comment);
            taskService.complete(taskEntity.getId(), variables);

            // 任务流转完成后，更新当前任务关联情况
            CurrentTask currentTask = new CurrentTask();
            currentTask.setBusinessId(bussKey);
            currentTask.setTaskId(taskEntity.getId());
            currentTask.setStatus(nextNode.getNodeStatusCode());
            if (designOprId != null && !"".equals(designOprId)) {
                log.info("指定个人处理任务");
                currentTask.setType(1);
                currentTask.setUserId(designOprId);
                currentTask.setRoleId("");
            } else {
                currentTask.setType(2);
                currentTask.setUserId("");
                currentTask.setRoleId(nextNode.getRoleId());
            }
            currentTask.setRoleId(nextNode.getRoleId());
            currentTask.setNodeId(nextNode.getNodeId());
            currentTask.setUpdatedAt(new Date());
            currentTaskService.updateByPrimaryKeySelective(currentTask);
            log.info("当前任务更新--------------------------------->>");

            // 任务流转完成之后-- 添加历史记录
            AuditLog auditLog = new AuditLog();
            auditLog.setBusinessId(bussKey);
            auditLog.setComment(comment);
            // 状态码类型
            auditLog.setStatusType(curNode.getStatusType());
            auditLog.setResultCode(curNode.getNodeStatusCode() == null ? "0" : curNode.getNodeStatusCode());
            //李国庆 11-5 为了区分财务放款审核通过，退回
            String examineCode = String.valueOf(param.get("examineCode"));
            auditLog.setExamineCode(examineCode);
            if ("1".equals(examineCode)) {
                auditLog.setResult(curNode.getNodeName() + "通过");
            } else if ("2".equals(examineCode)) {
                auditLog.setResult(curNode.getNodeName() + "拒绝");
            } else if ("3".equals(examineCode)) {
                auditLog.setResult(curNode.getNodeName() + "退回");
            } else {
                auditLog.setResult(curNode.getNodeName() + "完成");
            }
            auditLog.setInstanceId(procInstId);
            auditLog.setNodeId(nodeId);
            auditLog.setUserId(userId);
            auditLog.setUserName(userName);
            auditLog.setTaskId(taskEntity.getId());
            auditLog.setCreateAt(new Date());
            auditLog.setCreateById(userId);
            auditLogService.insertSelective(auditLog);
            log.info("添加历史日志记录--------------------------------->>");

            TaskEntity nextTask = this.findRunTaskByInstId(procInstId);
            Map<String, Object> returnParam = new HashMap<>();
            if (nextTask == null) {
                log.info("任务实例未找到------>>任务已终结");
                this.dealReturnEndParam(returnParam, nextNode);
            } else {
                log.info("下一节点任务信息：{}", nextTask.toString());
                this.dealReturnParam(returnParam, nextTask);
            }
            result.setMessage(taskEntity.getName() + "节点推动成功!");
            result.setData(returnParam);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("推动工作流节点接口调用异常，\n exp-msg:{}, \n stack-trace:{}", e.getMessage(), e.getStackTrace());
            result.setMessage("推动工作流节点接口调用异常, exp-msg:" + e.getMessage());
            result.setSuccess(false);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return result;
    }

    /**
     * 处理工作流运行时返回信息
     *
     * @param returnParam 返回参数信息
     * @param taskEntity  当前任务实体
     */
    private void dealReturnParam(Map<String, Object> returnParam, TaskEntity taskEntity) {
        if (taskEntity != null) {
            String[] status = taskEntity.getDescription().split(":");
            String[] users = taskEntity.getAssignee().split(":");
            if ("DesignatedOperator".equals(users[1])) {
                log.info("指定用户操作");
                returnParam.put("oprTyp", "1");
                returnParam.put("userId", users[0]);
            } else {
                log.info("操作角色");
                returnParam.put("oprTyp", "2");
                returnParam.put("roleId", users[0]);
            }
            returnParam.put("currStateCode", status[0]);
            returnParam.put("currStateName", status[1]);
            returnParam.put("currentTaskId", taskEntity.getId());
            returnParam.put("currentNodeId", taskEntity.getTaskDefinitionKey());
            returnParam.put("currentNodeName", taskEntity.getName());
            returnParam.put("procInstId", taskEntity.getProcessInstanceId());
        }
    }

    /**
     * 处理工作流结束返回信息
     *
     * @param returnParam 返回参数信息
     * @param nextNode    终结节点信息
     */
    private void dealReturnEndParam(Map<String, Object> returnParam, WorkflowNodeDto nextNode) {
        if (nextNode != null) {
            returnParam.put("oprTyp", "0");
            returnParam.put("userId", "0");
            returnParam.put("currStateCode", nextNode.getNodeStatusCode());
            returnParam.put("currStateName", nextNode.getNodeStatusName());
        }
    }

}
